/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.ipti.br.tag.bean;

import org.ipti.br.tag.bean.dataManipulation.Month;
import org.ipti.br.tag.bean.dataManipulation.MonthlyFrequency;
import org.ipti.br.tag.bo.ActivityBO;
import org.ipti.br.tag.bo.ActorBO;
import org.ipti.br.tag.bo.DisciplineBO;
import org.ipti.br.tag.bo.OrganizationBO;
import org.ipti.br.tag.bo.SimpleFrequencyBO;
import org.ipti.br.tag.bo.UnityBO;
import org.ipti.br.tag.bo.UnityScheduleBO;
import org.ipti.br.tag.bo.WorkBO;
import org.ipti.br.tag.entity.Activity;
import org.ipti.br.tag.entity.Actor;
import org.ipti.br.tag.entity.Discipline;
import org.ipti.br.tag.entity.Human;
import org.ipti.br.tag.entity.Organization;
import org.ipti.br.tag.entity.SimpleFrequency;
import org.ipti.br.tag.entity.Unity;
import org.ipti.br.tag.entity.UnitySchedule;
import org.ipti.br.tag.entity.WorkTopic;
import org.ipti.br.tag.entity.enums.Reference;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import javax.annotation.PostConstruct;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpServletResponse;
import org.ipti.br.tag.util.LoggerUtil;

/**
 *
 * @author israel
 */
@Named
@ConversationScoped
public class FrequencyMB extends AppBaseBean {
    private static final int DAY_OF_MONTH = Calendar.DAY_OF_MONTH;
    private static final int DEFAULT_BUFFER_SIZE = 10240;

    @Inject private SessionBean sessionBean;
    @Inject private OrganizationBO organizationBO;
    @Inject private UnityBO unityBO;
    @Inject private ActorBO actorBO;
    @Inject private DisciplineBO disciplineBO;
    @Inject private SimpleFrequencyBO simpleFrequencyBO;
    @Inject private UnityScheduleBO unityScheduleBO;
    @Inject private ActivityBO activityBO;
    @Inject private WorkBO workBO;
    @Inject private Conversation conversation;
    
    private Unity unity;
    private Discipline discipline;
    private Organization organization;
    private SimpleFrequency simpleFrequency;
    
    private List<Unity> unityList;
    private MonthlyFrequency matriculated, allocated;
    private MonthlyFrequency replacementAssiduity;
    private List<SimpleFrequency> replacement;
    private List<Date> dayList;
    
    private List<Activity> activities;
    private UnitySchedule scheduleSelected;
    private Calendar daySelected;
    private Integer code;
    
    private boolean loadedTable = false;
    private Month month;
    private int year = this.getActualYear();

    @PostConstruct
    public void init() {
        conversation.begin();
        
        try {
            organization = organizationBO.find(Long.parseLong(getParameter("organization")));
        } catch (Exception e) {
            this.redirect(DOMAIN);
        }
        
        loadUnities();
        replacement = new ArrayList<SimpleFrequency>();
    }

    public void loadUnities() {
        unityList = unityBO.unityChildren(sessionBean.getLoggedActor().getUnity(), organization, year);
    }

    public void loadTable() {
        if (!validateDate()) {
            System.out.println("Date!!!!!!!");
            loadedTable = false;
            
        }else{
        loadDayList();
        List<Actor> actors = actorBO.searchActorPerUnitiesAllocated(unity,discipline);
        allocated = new MonthlyFrequency(actors,dayList);
        
        actors = actorBO.searchActorPerUnitiesMatriculated(unity);
        matriculated = new MonthlyFrequency(actors,dayList);
        replacementAssiduity = new MonthlyFrequency(actors);
        constructTable();
//        loadReplacement();
        loadedTable = true;
        }
    }

    /**
     * Carrega a lista de dias que possuem atividade no mês.Quando possui disciplina, lista apenas as atividades da disciplina escolhida.
     */
    public void loadDayList() {
        dayList = unityScheduleBO.loadDays(unity, discipline, month, year);

        if (dayList == null || dayList.isEmpty()) {
            addErrorMessage("simpleFrequencyForm", "Não existe agenda cadastrada para essa unidade", "");
        }
    }

    public void constructTable() {
        simpleFrequencyBO.loadFrequencys(matriculated, discipline, unity);
        simpleFrequencyBO.loadFrequencys(allocated, discipline, unity);
    }
    
    
    public void prepareActivities(int selected) {
        daySelected = Calendar.getInstance();
        daySelected.setTime(dayList.get(selected));
        
        int indexDay = simpleFrequencyBO.getRepetitions(dayList, selected);
        scheduleSelected = unityScheduleBO.findBy(unity, discipline, daySelected, indexDay);
        activities = activityBO.list(daySelected, scheduleSelected);
    }
    
    public void addActivity() {
        Activity activity = new Activity(daySelected, scheduleSelected);
        WorkTopic topic = workBO.findCode(organization, code);
        
        if (topic == null) {
            topic = new WorkTopic("Synapse");
            topic.setCode(code);
            workBO.createTopic(topic, year);
        }
        
        activity.setWorkTopic(topic);
        activityBO.create(activity);
        activities.add(activity);
        addInfoMessage(null, "Parabéns! :)", "A atividade foi cadastrada com sucesso");
    }
    
    public void removeActivity(Activity activity) {
        System.out.println(daySelected.getTime().toString() + " " + activity.toString());
        activityBO.remove(activity);
        activities.remove(activity);
        addInfoMessage(null, "Sucesso!", "Poxa, dói tando quando as pessoas excluem coisas de mim :/");
    }

    public void save() {
        try {
            simpleFrequencyBO.saveFrequencys(matriculated, discipline, unity);
            simpleFrequencyBO.saveFrequencys(allocated, discipline, unity);

            loadReplacement();
            addInfoMessage("simpleFrequencyForm", "Operação realizada com sucesso", null);
        } catch (Exception ex) {
            addErrorMessage("simpleFrequencyForm", "Operação não pôde ser realizada", null);
        }
    }

    public void loadReplacement() {
        long reference = unity.getId();
        Reference refT = discipline == null ? Reference.UNITY : Reference.UNITY_SCHEDULE;
        
        Calendar initialDate = Calendar.getInstance();
        initialDate.set(year, month.ordinal(), 1, 0, 0, 0);

        Calendar finalDate = Calendar.getInstance();
        finalDate.set(year, month.ordinal(), initialDate.getActualMaximum(Calendar.DAY_OF_MONTH), 0, 0, 0);

        replacement = simpleFrequencyBO.simpleFrequencysPerReferenceDates(refT, reference, initialDate, finalDate);
    }

    public void preEditReplacement() {
        SimpleFrequency sfTemp;
        if (simpleFrequency.getReplacementDate() != null) {
            replacementAssiduity.load(simpleFrequency.getReplacementDate().getTime());
            for (int i = 0; i < replacementAssiduity.getActors().size(); i++) {
                sfTemp = simpleFrequencyBO.findByFields(simpleFrequency.getReplacementDate(),
                        matriculated.getActors().get(i).getId(), simpleFrequency.getReference(), simpleFrequency.getReferenceID());
                if (sfTemp == null) {
                    replacementAssiduity.getAssiduity()[i][0] = false;
                } else {
                    replacementAssiduity.getAssiduity()[i][0] = true;
                }
            }
        } else {
            replacementAssiduity.load(new Date());
            for (int i = 0; i < replacementAssiduity.getActors().size(); i++) {
                replacementAssiduity.getAssiduity()[i][0] = false;
            }
        }
    }

    public void saveReplacement() {
        try {
            Calendar cal = Calendar.getInstance();
            cal.setTime(replacementAssiduity.getDays().get(0));
            simpleFrequency.setReplacementDate(cal);
            simpleFrequencyBO.edit(simpleFrequency);
            
            simpleFrequencyBO.replaceFrequencys(replacementAssiduity, simpleFrequency, discipline, unity);
            addInfoMessage("simpleFrequencyForm:messages", "Operação realizada com sucesso", null);
        } catch (Exception ex) {
            addErrorMessage("simpleFrequencyForm:messages", "Operação não pôde ser realizada", null);
            LoggerUtil.log("SimpleFrequencyBean:saveReplacement", Level.SEVERE, "Não salvou", ex);
        }
    }

    public void export() {
        if (dayList.size() > 0 && matriculated.getActors().size() > 0) {
            List<String> namesList = new ArrayList<String>();
            for (Actor actor : matriculated.getActors()) {
                namesList.add(((Human) actor.getPerson()).getName());
            }

            FacesContext facesContext = getFacesContext();
            ExternalContext externalContext = facesContext.getExternalContext();
            HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();

            String path = "resources/pdf/Frequencia" + unity.getName() + " " + month.ordinal() + " " + year + ".pdf";
            path = path.replaceAll("//W", "");
            path = externalContext.getRealPath(path);
            simpleFrequencyBO.export(path ,year, month, namesList, unity.getName(), dayList);
            
            File file = new File(path);
            BufferedInputStream input = null;
            BufferedOutputStream output = null;

            try {
                input = new BufferedInputStream(new FileInputStream(file), DEFAULT_BUFFER_SIZE);
                response.reset();
                response.setHeader("Content-Type", "application/pdf");
                response.setHeader("Content-Length", String.valueOf(file.length()));
                response.setHeader("Content-Disposition", "inline; filename=\"" + file.getName() + "\"");
                output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);
                byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
                int length;
                while ((length = input.read(buffer)) > 0) {
                    output.write(buffer, 0, length);
                }
                output.flush();
            } catch (Exception ex) {
                LoggerUtil.log("SimpleFrequencyBean:export", Level.SEVERE, "Não enviou", ex);
            } finally {
                try {
                    output.close();
                    input.close();
                } catch (IOException e) {
                    LoggerUtil.log("SimpleFrequencyBean:export", Level.SEVERE, "Não fechou", e);
                }
            }
            facesContext.responseComplete();
        }
    }
    
    public boolean validateDate() {
        Calendar firstDay = Calendar.getInstance(), finalDay = Calendar.getInstance();
        firstDay.set(year, month.ordinal(), 1);
        finalDay.set(year, month.ordinal(), firstDay.getMaximum(Calendar.DAY_OF_MONTH));
        if((unity != null && unity.getDeactivated() != null && firstDay.after(unity.getDeactivated())) &&
            (unity != null && unity.getActivated() != null && finalDay.before(unity.getActivated()))) {
            return false;
        } else if(unity != null && unity.getActivated() != null && finalDay.before(unity.getActivated())) {
            return false;
        }
        return true;
    }
    
    public List<Discipline> getDisciplines(){
        return disciplineBO.findAllOrder();
    }
    
    public Integer getActualYear(){
        return Calendar.getInstance().get(Calendar.YEAR);
    }

    public Month[] getMonths() {
        return Month.values();
    }

    public MonthlyFrequency getMatriculated() {
        return matriculated;
    }

    public void setMatriculated(MonthlyFrequency actorList) {
        this.matriculated = actorList;
    }

    public MonthlyFrequency getAllocated() {
        return allocated;
    }

    public void setAllocated(MonthlyFrequency allocatedActors) {
        this.allocated = allocatedActors;
    }

    public List<Date> getDayList() {
        return dayList;
    }

    public void setDayList(List<Date> dayList) {
        this.dayList = dayList;
    }

    public int getDAY_OF_MONTH() {
        return DAY_OF_MONTH;
    }

    public List<SimpleFrequency> getReplacement() {
        return replacement;
    }

    public void setReplacement(List<SimpleFrequency> replacement) {
        this.replacement = replacement;
    }

    public MonthlyFrequency getReplacementAssiduity() {
        return replacementAssiduity;
    }

    public void setReplacementAssiduity(MonthlyFrequency replacementAssiduity) {
        this.replacementAssiduity = replacementAssiduity;
    }

    public Unity getUnity() {
        return unity;
    }

    public void setUnity(Unity unity) {
        this.unity = unity;
    }

    public Organization getOrganization() {
        return organization;
    }

    public void setOrganization(Organization organization) {
        this.organization = organization;
    }

    public SimpleFrequency getSimpleFrequency() {
        return simpleFrequency;
    }

    public void setSimpleFrequency(SimpleFrequency simpleFrequency) {
        this.simpleFrequency = simpleFrequency;
    }

    public List<Unity> getUnityList() {
        return unityList;
    }

    public void setUnityList(List<Unity> unityList) {
        this.unityList = unityList;
    }

    public Month getMonth() {
        return month;
    }

    public void setMonth(Month month) {
        this.month = month;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public Discipline getDiscipline() {
        return discipline;
    }

    public void setDiscipline(Discipline discipline) {
        this.discipline = discipline;
    }

    public List<Activity> getActivities() {
        return activities;
    }

    public void setActivities(List<Activity> activities) {
        this.activities = activities;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public UnitySchedule getScheduleSelected() {
        return scheduleSelected;
    }

    public void setScheduleSelected(UnitySchedule scheduleSelected) {
        this.scheduleSelected = scheduleSelected;
    }

    public boolean isLoadedTable() {
        return loadedTable;
    }

    public void setLoadedTable(boolean loadedTable) {
        this.loadedTable = loadedTable;
    }
    
    
}